package crmdna.member;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.gson.Gson;
import com.googlecode.objectify.ObjectifyFilter;

import crmdna.client.Client;
import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;
import crmdna.common.OfyService;
import crmdna.common.contact.ContactProp;
import crmdna.group.Group;
import crmdna.group.Group.GroupProp;
import crmdna.member.MemberEntity.MemberFactory;
import crmdna.practice.Practice;
import crmdna.practice.Practice.PracticeProp;
import crmdna.program.Program;
import crmdna.program.ProgramProp;
import crmdna.programtype.ProgramType;
import crmdna.programtype.ProgramTypeProp;
import crmdna.teacher.Teacher;
import crmdna.teacher.Teacher.TeacherProp;
import crmdna.user.User;
import crmdna.user.User.Action;
import crmdna.user.User.ResourceType;
import crmdna.user.UserCore;
import crmdna.venue.Venue;
import crmdna.venue.Venue.VenueProp;

public class MemberSaverTest {

	private final LocalServiceTestHelper datastoreHelper = new LocalServiceTestHelper(
			new LocalDatastoreServiceTestConfig().setApplyAllHighRepJobPolicy());

	private final String client = "isha";
	private final String invalidClient = "invalid";
	private final String validUser = "valid@login.com";
	private final String validUser2 = "valid2@login.com";
	private final String invalidUser = "invalid@login.com";
	private final String userWithPermission = "userwithpermission@login.com";
	private GroupProp sgp;
	private GroupProp kl;
	private GroupProp sydney;
	private GroupProp iyc;

	private PracticeProp shambhavi, mysticEye, ishaKriya;

	private ProgramTypeProp shambhavi2Day, mysticEye1Day;

	ProgramProp shambhavi201405, mysticEye201401, sathsang201405;

	MemberProp thulasi;
	String sgpUser = "sgpuser@valid.com";

	@Before
	public void setUp() {
		datastoreHelper.setUp();
		ObjectifyFilter.complete();

		Client.create(client);
		sgp = Group.create(client, "Singapore", User.SUPER_USER);
		assertEquals(1, sgp.groupId);

		kl = Group.create(client, "Malaysia/KL", User.SUPER_USER);
		assertEquals(2, kl.groupId);

		sydney = Group.create(client, "Australia/Sydney", User.SUPER_USER);
		assertEquals(3, sydney.groupId);

		iyc = Group.create(client, "India/Isha Yoga Center", User.SUPER_USER);
		assertEquals(4, iyc.groupId);

		User.create(client, validUser, sgp.groupId, User.SUPER_USER);
		assertEquals(1, UserCore.get(client, validUser).toProp().userId);

		User.create(client, validUser2, sgp.groupId, User.SUPER_USER);
		assertEquals(2, UserCore.get(client, validUser2).toProp().userId);

		User.create(client, userWithPermission, sgp.groupId, User.SUPER_USER);
		assertEquals(3,
				UserCore.get(client, userWithPermission).toProp().userId);
		User.addOrDeletePrivilege(client, userWithPermission,
				ResourceType.INTERACTION, 0, Action.WRITE, true,
				User.SUPER_USER);

		shambhavi = Practice.create("isha", "Shambhavi", User.SUPER_USER);
		mysticEye = Practice.create("isha", "MysticEye", User.SUPER_USER);
		ishaKriya = Practice.create("isha", "IshaKriya", User.SUPER_USER);

		Set<Long> sathsangPracticeIds = new HashSet<>();
		sathsangPracticeIds.add(shambhavi.practiceId);
		sathsangPracticeIds.add(mysticEye.practiceId);

		Set<Long> practiceIds = new HashSet<>();
		practiceIds.add(shambhavi.practiceId);
		ProgramTypeProp shambhavi2Day = ProgramType.create("isha", "Shambhavi",
				practiceIds, User.SUPER_USER);

		practiceIds.clear();
		practiceIds.add(mysticEye.practiceId);
		ProgramTypeProp mysticEye1Day = ProgramType.create("isha", "MysticEye",
				practiceIds, User.SUPER_USER);

		ProgramTypeProp sathsang = ProgramType.create("isha", "Sathsang", null,
				User.SUPER_USER);

		GroupProp chennai = Group.create("isha", "Chennai", User.SUPER_USER);

		VenueProp giis = Venue.create("isha", "GIIS", "GIIS", sgp.groupId,
				User.SUPER_USER);
		VenueProp expo = Venue.create("isha", "Expo", "Expo", sgp.groupId,
				User.SUPER_USER);

		TeacherProp nidhi = Teacher.create("isha",
				"nidhi.jain@ishafoundation.org", sgp.groupId, User.SUPER_USER);
		TeacherProp sadhguru = Teacher.create("isha",
				"sadhguru@ishafoundation.org", sgp.groupId, User.SUPER_USER);

		shambhavi201405 = Program.create("isha", sgp.groupId,
				shambhavi2Day.programTypeId, giis.venueId, nidhi.teacherId,
				20140503, 20140504, 1, null, 0, null, User.SUPER_USER);

		mysticEye201401 = Program.create("isha", sgp.groupId,
				mysticEye1Day.programTypeId, expo.venueId, sadhguru.teacherId,
				20140503, 20140504, 1, null, 0, null, User.SUPER_USER);

		sathsang201405 = Program.create("isha", sgp.groupId,
				sathsang.programTypeId, giis.venueId, nidhi.teacherId,
				20140503, 20140503, 1, null, 0, null, User.SUPER_USER);

		User.create("isha", sgpUser, sgp.groupId, User.SUPER_USER);
		User.addOrDeletePrivilege("isha", sgpUser, ResourceType.GROUP,
				sgp.groupId, Action.WRITE, true, User.SUPER_USER);
	}

	@After
	public void tearDown() {
		ObjectifyFilter.complete();
		datastoreHelper.tearDown();
	}

	@Test
	public void addOrDeleteGroupTest() {
		ContactProp contact = new ContactProp();
		contact.email = "Sathya.t@IshaFoundation.org";
		contact.mobilePhone = "+6598361844";
		contact.homePhone = "+6565227030";

		MemberProp prop = Member.create(client, sgp.groupId, contact, false,
				User.SUPER_USER);

		// user cannot be invalid
		try {
			Member.addOrDeleteGroup(client, prop.memberId, 100, true,
					invalidUser);
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_INVALID_USER, ex.statusCode);
		}

		// member should exist
		try {
			Member.addOrDeleteGroup(client, 3456, kl.groupId, true, validUser);
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
		}

		// center should exist
		try {
			Member.addOrDeleteGroup(client, prop.memberId, 100, true, validUser);
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
		}

		// add kl
		Member.addOrDeleteGroup(client, prop.memberId, kl.groupId, true,
				validUser);
		ObjectifyFilter.complete();
		prop = MemberLoader.safeGet(client, prop.memberId, User.SUPER_USER)
				.toProp();
		assertEquals(2, prop.groupIds.size());
		assertTrue(prop.groupIds.contains(sgp.groupId));
		assertTrue(prop.groupIds.contains(kl.groupId));

		// can add the same center again
		Member.addOrDeleteGroup(client, prop.memberId, kl.groupId, true,
				validUser);
		ObjectifyFilter.complete();
		prop = MemberLoader.safeGet(client, prop.memberId, User.SUPER_USER)
				.toProp();
		assertEquals(2, prop.groupIds.size());
		assertTrue(prop.groupIds.contains(sgp.groupId));
		assertTrue(prop.groupIds.contains(kl.groupId));

		// remove center
		Member.addOrDeleteGroup(client, prop.memberId, kl.groupId, false,
				validUser);
		ObjectifyFilter.complete();
		prop = MemberLoader.safeGet(client, prop.memberId, User.SUPER_USER)
				.toProp();
		assertEquals(1, prop.groupIds.size());
		assertTrue(prop.groupIds.contains(sgp.groupId));
		assertTrue(!prop.groupIds.contains(kl.groupId));

		// can remove center again
		Member.addOrDeleteGroup(client, prop.memberId, kl.groupId, false,
				validUser);
		ObjectifyFilter.complete();
		prop = MemberLoader.safeGet(client, prop.memberId, User.SUPER_USER)
				.toProp();
		assertEquals(1, prop.groupIds.size());
		assertTrue(prop.groupIds.contains(sgp.groupId));
		assertTrue(!prop.groupIds.contains(kl.groupId));

		// there should be atleast 1 center
		try {
			Member.addOrDeleteGroup(client, prop.memberId, sgp.groupId, false,
					validUser);
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_PRECONDITION_FAILED, ex.statusCode);
		}
	}

	@Test
	public void populateDependantIndexFieldsTest() {

		assertTrue(false);

		// MemberEntity memberEntity = new MemberEntity();
		// try {
		// MemberCore.populateDependantIndexFields(memberEntity);
		// } catch (APIException e) {
		// assertEquals(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED,
		// e.statusCode);
		// }
		//
		// //email specified but not name
		// memberEntity.email = "emailsathya@gmail.com";
		// MemberCore.populateDependantIndexFields(memberEntity);
		// assertEquals(memberEntity.name, memberEntity.email);
		// assertEquals(memberEntity.nameFirstChar, "e");
		//
		// //specify phone number but not email or name
		// memberEntity = new MemberEntity();
		// memberEntity.mobilePhone = "+6598361844";
		// MemberCore.populateDependantIndexFields(memberEntity);
		// assertEquals(memberEntity.name, memberEntity.mobilePhone);
		// assertEquals(memberEntity.nameFirstChar, "+");
		//
		// //specify name and email
		// memberEntity = new MemberEntity();
		// memberEntity.firstName = "Sathyanarayanan";
		// memberEntity.email = "sathya.t@ishafoundation.org";
		// MemberCore.populateDependantIndexFields(memberEntity);
		// assertEquals(memberEntity.name, "sathyanarayanan");
		// assertEquals(memberEntity.nameFirstChar, "s");
	}

	@Test
	public void addOrDeleteProgramTest_toberemoved() {
		assertTrue(false);
	}

	@Test
	public void bulkUploadParticipantsTest() {
		assertEquals(true, false);
	}

	@Test
	public void bulkUpdateWithoutValidations() {
		assertTrue(false);
	}

	@Test
	public void bulkUploadProgramParticipants() {
		assertTrue(false);
	}

	@Test
	public void ensureValidTest() {
		assertTrue(false);
	}

	@Test
	public void addOrDeleteProgramTest() {
		ContactProp contactDetailProp = new ContactProp();
		contactDetailProp.email = "simansmile@yahoo.com";

		MemberProp narasimhan = Member.create(client, sgp.groupId,
				contactDetailProp, false, User.SUPER_USER);

		contactDetailProp.email = "thulasidhar@gmail.com";
		MemberProp thulasi = Member.create(client, sgp.groupId,
				contactDetailProp, false, User.SUPER_USER);

		VenueProp adiYogiAlayam = Venue.create(client, "Adi yogi aalayam",
				"Adi yogi aalamay", iyc.groupId, User.SUPER_USER);

		PracticeProp suryaKriya = Practice.create(client, "surya kriya",
				User.SUPER_USER);
		PracticeProp upaYoga = Practice.create(client, "upa yoga",
				User.SUPER_USER);
		PracticeProp angamardhana = Practice.create(client, "angamardhana",
				User.SUPER_USER);
		PracticeProp yogaAsanas = Practice.create(client, "yoga asanas",
				User.SUPER_USER);

		Set<Long> practiceIds = new HashSet<Long>();
		practiceIds.add(suryaKriya.practiceId);
		practiceIds.add(upaYoga.practiceId);
		practiceIds.add(angamardhana.practiceId);
		practiceIds.add(yogaAsanas.practiceId);

		ProgramTypeProp hatayoga21day = ProgramType.create(client,
				"Hata yoga 21 day", practiceIds, User.SUPER_USER);

		TeacherProp sheela = Teacher.create(client,
				"sheela.r@ishafoundation.org", iyc.groupId, User.SUPER_USER);

		ProgramProp hatayoga21day2013 = Program.create(client, iyc.groupId,
				hatayoga21day.programTypeId, adiYogiAlayam.venueId,
				sheela.teacherId, 20130701, 20130721, 1, null, 0, null,
				User.SUPER_USER);

		List<Long> memberIds = new ArrayList<Long>();

		// can call with empty list

		Member.addOrDeleteProgram(client, narasimhan.memberId,
				hatayoga21day2013.programId, true, User.SUPER_USER);

		// clear session cache
		ObjectifyFilter.complete();
		OfyService.ofy(client).clear();

		MemberProp thulasiProp = MemberLoader.safeGet(client, thulasi.memberId,
				User.SUPER_USER).toProp();
		assertEquals(1, thulasiProp.programIds.size());
		assertTrue(thulasiProp.programIds.contains(hatayoga21day2013.programId));
		assertEquals(1, thulasiProp.programTypeIds.size());
		assertTrue(thulasiProp.programTypeIds
				.contains(hatayoga21day.programTypeId));
		assertEquals(4, thulasiProp.practiceIds.size());
		assertTrue(thulasiProp.practiceIds.contains(suryaKriya.practiceId));
		assertTrue(thulasiProp.practiceIds.contains(upaYoga.practiceId));
		assertTrue(thulasiProp.practiceIds.contains(angamardhana.practiceId));
		assertTrue(thulasiProp.practiceIds.contains(yogaAsanas.practiceId));

		MemberProp narasimhanProp = MemberLoader.safeGet(client,
				narasimhan.memberId, User.SUPER_USER).toProp();
		assertEquals(1, narasimhanProp.programIds.size());
		assertTrue(narasimhanProp.programIds
				.contains(hatayoga21day2013.programId));
		assertEquals(1, narasimhanProp.programTypeIds.size());
		assertTrue(narasimhanProp.programTypeIds
				.contains(hatayoga21day.programTypeId));
		assertEquals(4, narasimhanProp.practiceIds.size());
		assertTrue(narasimhanProp.practiceIds.contains(suryaKriya.practiceId));
		assertTrue(narasimhanProp.practiceIds.contains(upaYoga.practiceId));
		assertTrue(narasimhanProp.practiceIds.contains(angamardhana.practiceId));
		assertTrue(narasimhanProp.practiceIds.contains(yogaAsanas.practiceId));

		// add again
		Member.addOrDeleteProgram(client, narasimhan.memberId,
				hatayoga21day.programTypeId, true, validUser);
		ObjectifyFilter.complete();
		OfyService.ofy(client).clear();

		thulasiProp = MemberLoader.safeGet(client, thulasi.memberId,
				User.SUPER_USER).toProp();
		assertEquals(1, thulasiProp.programIds.size());
		assertTrue(thulasiProp.programIds.contains(hatayoga21day2013.programId));
		assertEquals(1, thulasiProp.programTypeIds.size());
		assertTrue(thulasiProp.programTypeIds
				.contains(hatayoga21day.programTypeId));
		assertEquals(4, thulasiProp.practiceIds.size());
		assertTrue(thulasiProp.practiceIds.contains(suryaKriya.practiceId));
		assertTrue(thulasiProp.practiceIds.contains(upaYoga.practiceId));
		assertTrue(thulasiProp.practiceIds.contains(angamardhana.practiceId));
		assertTrue(thulasiProp.practiceIds.contains(yogaAsanas.practiceId));

		narasimhanProp = MemberLoader.safeGet(client, narasimhan.memberId,
				User.SUPER_USER).toProp();
		assertEquals(1, narasimhanProp.programIds.size());
		assertTrue(narasimhanProp.programIds
				.contains(hatayoga21day2013.programId));
		assertEquals(1, narasimhanProp.programTypeIds.size());
		assertTrue(narasimhanProp.programTypeIds
				.contains(hatayoga21day.programTypeId));
		assertEquals(4, narasimhanProp.practiceIds.size());
		assertTrue(narasimhanProp.practiceIds.contains(suryaKriya.practiceId));
		assertTrue(narasimhanProp.practiceIds.contains(upaYoga.practiceId));
		assertTrue(narasimhanProp.practiceIds.contains(angamardhana.practiceId));
		assertTrue(narasimhanProp.practiceIds.contains(yogaAsanas.practiceId));

		// delete member
		Member.addOrDeleteProgram(client, narasimhan.memberId,
				hatayoga21day.programTypeId, false, validUser);
		ObjectifyFilter.complete();
		OfyService.ofy(client).clear();

		// exception if client is invalid
		try {
			Member.addOrDeleteProgram(invalidClient, narasimhan.memberId,
					hatayoga21day2013.programId, true, User.SUPER_USER);
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
		}

		// program id should be valid
		try {
			Member.addOrDeleteProgram(client, narasimhan.memberId, 938, true,
					User.SUPER_USER); // invalid program id
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
		}

		// user should be a valid user
		try {
			Member.addOrDeleteProgram(client, narasimhan.memberId,
					hatayoga21day2013.programId, true, invalidUser);
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_INVALID_USER, ex.statusCode);
		}
	}

	// @Test
	// public void bulkCreateWithoutValidationsTest() {
	//
	// ContactProp thulasi = new ContactProp();
	// thulasi.email = "thulasidhar@gmail.com";
	// thulasi.firstName = "Thulasidhar";
	// thulasi.lastName = "Kosalram";
	// thulasi.mobilePhone = "+6592705371";
	//
	// ContactProp narasimhan = new ContactProp();
	// narasimhan.email = "simansmile@yahoo.com";
	// narasimhan.firstName = "Narasimhan";
	// narasimhan.mobilePhone = "+6597302205";
	//
	// VenueProp adiYogiAlayam = Venue.create(client, "Adi yogi aalayam",
	// "Adi yogi aalamay", iyc.groupId, User.SUPER_USER);
	//
	// PracticeProp suryaKriya = Practice.create(client, "surya kriya",
	// User.SUPER_USER);
	// PracticeProp upaYoga = Practice.create(client, "upa yoga",
	// User.SUPER_USER);
	// PracticeProp angamardhana = Practice.create(client, "angamardhana",
	// User.SUPER_USER);
	// PracticeProp yogaAsanas = Practice.create(client, "yoga asanas",
	// User.SUPER_USER);
	//
	// Set<Long> practiceIds = new HashSet<Long>();
	// practiceIds.add(suryaKriya.practiceId);
	// practiceIds.add(upaYoga.practiceId);
	// practiceIds.add(angamardhana.practiceId);
	// practiceIds.add(yogaAsanas.practiceId);
	//
	// ProgramTypeProp hatayoga21day = ProgramType.create(client,
	// "Hata yoga 21 day", practiceIds, User.SUPER_USER);
	//
	// TeacherProp sheela = Teacher.create(client,
	// "sheela.r@ishafoundation.org", iyc.groupId, User.SUPER_USER);
	//
	// ProgramProp hatayoga21day2013 = Program.create(client, iyc.groupId,
	// hatayoga21day.programTypeId, adiYogiAlayam.venueId,
	// sheela.teacherId, 20130701, 20130721, 1, null, 0, null,
	// User.SUPER_USER);
	//
	// List<ContactProp> contactDetailProps = new ArrayList<ContactProp>();
	// contactDetailProps.add(null);
	// contactDetailProps.add(null);
	//
	// Member.bulkCreateWithoutValidations(client, contactDetailProps,
	// hatayoga21day2013.programId);
	//
	// contactDetailProps.clear();
	// contactDetailProps.add(null);
	// contactDetailProps.add(thulasi);
	// contactDetailProps.add(null);
	// contactDetailProps.add(narasimhan);
	// contactDetailProps.add(null);
	//
	// List<Long> memberIds = Member.bulkCreateWithoutValidations(client,
	// contactDetailProps, hatayoga21day2013.programId);
	// assertEquals(5, memberIds.size());
	// // same order should be preserved
	// assertEquals(null, memberIds.get(0));
	// assertEquals(1, memberIds.get(1) + 0);
	// assertEquals(null, memberIds.get(2));
	// assertEquals(2, memberIds.get(3) + 0);
	// assertEquals(null, memberIds.get(4));
	//
	// // clear cache
	// ObjectifyFilter.complete();
	// OfyService.ofy(client).clear();
	//
	// MemberProp thulasiProp = Member.safeGet(client, 1, User.SUPER_USER)
	// .toProp();
	// assertEquals("thulasidhar@gmail.com", thulasiProp.contact.email);
	// assertEquals("Thulasidhar Kosalram", thulasiProp.contact.firstName
	// + " " + thulasiProp.contact.lastName);
	// assertEquals("+6592705371", thulasiProp.contact.mobilePhone);
	// assertEquals(1, thulasiProp.programIds.size());
	// assertTrue(thulasiProp.programIds.contains(hatayoga21day2013.programId));
	// assertEquals(1, thulasiProp.programTypeIds.size());
	// assertTrue(thulasiProp.programTypeIds
	// .contains(hatayoga21day.programTypeId));
	// assertEquals(4, thulasiProp.practiceIds.size());
	// assertTrue(thulasiProp.practiceIds.contains(suryaKriya.practiceId));
	// assertTrue(thulasiProp.practiceIds.contains(upaYoga.practiceId));
	// assertTrue(thulasiProp.practiceIds.contains(yogaAsanas.practiceId));
	// assertTrue(thulasiProp.practiceIds.contains(angamardhana.practiceId));
	//
	// List<MemberProp> matches = Member.query(client, "thulasidhar", null,
	// null, null, null, validUser);
	// assertEquals(1, matches.size());
	// assertEquals(thulasiProp.memberId, matches.get(0).memberId);
	//
	// MemberProp narasimhanProp = Member.safeGet(client, 2, User.SUPER_USER)
	// .toProp();
	// assertEquals("simansmile@yahoo.com", narasimhanProp.contact.email);
	// assertEquals("Narasimhan", narasimhanProp.contact.firstName);
	// assertEquals("+6597302205", narasimhanProp.contact.mobilePhone);
	// assertEquals(1, narasimhanProp.programIds.size());
	// assertTrue(narasimhanProp.programIds
	// .contains(hatayoga21day2013.programId));
	// assertEquals(1, narasimhanProp.programTypeIds.size());
	// assertTrue(narasimhanProp.programTypeIds
	// .contains(hatayoga21day.programTypeId));
	// assertEquals(4, narasimhanProp.practiceIds.size());
	// assertTrue(narasimhanProp.practiceIds.contains(suryaKriya.practiceId));
	// assertTrue(narasimhanProp.practiceIds.contains(upaYoga.practiceId));
	// assertTrue(narasimhanProp.practiceIds.contains(yogaAsanas.practiceId));
	// assertTrue(narasimhanProp.practiceIds.contains(angamardhana.practiceId));
	//
	// // exception if client is invalid
	// try {
	// Member.bulkCreateWithoutValidations(invalidClient,
	// contactDetailProps, hatayoga21day2013.programId);
	// assertTrue(false);
	// } catch (APIException ex) {
	// assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
	// }
	//
	// // program id should be valid
	// try {
	// Member.bulkCreateWithoutValidations(client, contactDetailProps, 992); //
	// invalid
	// // program
	// // id
	// assertTrue(false);
	// } catch (APIException ex) {
	// assertEquals(Status.ERROR_RESOURCE_NOT_FOUND, ex.statusCode);
	// }
	// }

}
